package edu.scut.course_management.service;

import edu.scut.course_management.dao.ResourceMapper;
import edu.scut.course_management.dao.SectionResourceMapper;
import edu.scut.course_management.exception.CustomException;
import edu.scut.course_management.po.Resource;
import edu.scut.course_management.po.Section;
import edu.scut.course_management.result.ResultCode;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.sql.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 课程资源管理服务
 * @author shawshank
 */
@Service
public class ResourceManagementService {

	@Autowired
	private ResourceMapper resourceMapper;
	@Autowired
	private SectionResourceMapper sectionResourceMapper;

	/**
	 * 上传课程资源
	 * @param sections 要上传资源的那几节课
	 * @param resourceNode 要上传的资源
	 * @param parentNodeId 要在哪个文件夹下上传课程资源，若 parentNodeId == 0，则表明该课程资源在顶级目录下
	 * @return 添加了资源后的那一级目录的文件列表
	 */
	public List<Resource> addResourceNode(List<Section> sections, Resource resourceNode, Integer parentNodeId) throws CustomException {

		// 判断父结点的有效性
		if (parentNodeId != 0) {
			if (resourceNodeValidity(sections, parentNodeId, true) == false) {
				throw new CustomException(ResultCode.RESOURCE_NODE_INVALID);
			}
			// 设置父结点
			resourceNode.setParentNodeId(parentNodeId);
		}

		// 判断该目录是否存在同名文件
		List<Resource> resourceList = null;
		if (parentNodeId == 0) {
			resourceList = sectionResourceMapper.findTopLevelResourceOfSection(sections.get(0));
		} else {
			resourceList = resourceMapper.getChildren(parentNodeId);
		}
		for (Resource resource: resourceList) {
			if (resourceNode.getName().equals(resource.getName())) {
				throw new CustomException(ResultCode.ALREADY_EXSIST_FILE_OF_SAME_NAME);
			}
		}

		// 上传文件
		try {
			// 设置上传日期为当天
			resourceNode.setUploadDate(new Date(System.currentTimeMillis()));
			// 创建课程资源结点
			resourceMapper.createResourceNode(resourceNode);
			// 在相对应的课程下添加课程资源
			Map<String, Object> params = new HashMap<>();
			params.put("sections", sections);
			params.put("resource", resourceNode);
			sectionResourceMapper.addResourceToSections(params);
		} catch (DataAccessException e) {
			e.printStackTrace();
			throw new CustomException(ResultCode.DATABASE_UPDATE_FAIL);
		}

		// 返回添加了资源后的那一级目录的文件列表
		if(parentNodeId == 0) {
			return sectionResourceMapper.findTopLevelResourceOfSection(sections.get(0));
		} else {
			return resourceMapper.getChildren(parentNodeId);
		}
	}

	/**
	 * 获得下一级文件列表
	 * @param parentNodeId 父结点编号
	 * @return 该父结点的所有孩子结点
	 */
	 public List<Resource> getFileListOfNextLevel(List<Section> sections,Integer parentNodeId) throws CustomException {
		// 返回顶级目录文件列表
		if (parentNodeId == 0) {
			return sectionResourceMapper.findTopLevelResourceOfSection(sections.get(0));
		} else {
			// 检测父结点有效性
			if (resourceNodeValidity(sections, parentNodeId, true) == false) {
				throw new CustomException(ResultCode.RESOURCE_NODE_INVALID);
			} else {
				return resourceMapper.getChildren(parentNodeId);
			}
		}
	}

	/**
	 * 删除课程资源
	 * @param sections 拥有这个资源结点的那几节课
	 * @param deletingResourceNodeId 要删除的资源结点编号
	 * @return 删除的那个资源结点原本所在目录的文件列表
	 */
	public List<Resource> deleteResourceNode(List<Section> sections, Integer deletingResourceNodeId) throws CustomException {
	 	// 判断结点有效性
		if (resourceNodeValidity(sections, deletingResourceNodeId, false) == false) {
			throw new CustomException(ResultCode.RESOURCE_NODE_INVALID);
		}
		// 获得要删除的资源结点的父结点标号
		Resource deletingResourceNode = resourceMapper.findResourceByNodeId(deletingResourceNodeId);
		Integer parentNodeId = deletingResourceNode.getParentNodeId();
		// 删除资源结点
		try {
			resourceMapper.deleteResourceNode(deletingResourceNodeId);
		} catch (DataAccessException e) {
			throw new CustomException(ResultCode.DATABASE_UPDATE_FAIL);
		}
		// 返回删除的那个资源结点原本所在目录的文件列表
		if (parentNodeId == null) {
			return sectionResourceMapper.findTopLevelResourceOfSection(sections.get(0));
		} else {
			return resourceMapper.getChildren(parentNodeId);
		}
	}

	/**
	 * 检测资源结点有效性的辅助函数
	 * @param sections 拥有这个父结点的那几节课
	 * @param parentNodeId 父结点编号
	 * @param folder 是否要求这个父结点是文件夹
	 * @return 该父结点是否有效
	 */
	private boolean resourceNodeValidity(List<Section> sections, Integer parentNodeId, boolean folder) {
		// 判断父结点是不是文件夹
		Resource parentResourceNode = resourceMapper.findResourceByNodeId(parentNodeId);
		if (folder  && (parentResourceNode == null || parentResourceNode.getIsFolder() == false)) {
			return false;
		}
		// 要上传资源的那几节课是否有要上传课程资源对应的父结点
		List<Section> ownerSections = sectionResourceMapper.findSectionsThroughResource(parentNodeId);
		for (Section section: sections) {
			if(!ownerSections.contains(section)) {
				return false;
			}
		}
		return true;
	}

}
